﻿#include "qmemorymonitor.h"
#include <QDebug>

QMemoryMonitor::QMemoryMonitor() {
}

QMemoryMonitor::~QMemoryMonitor() {
}

void QMemoryMonitor::getSystemPhysicalMemory(uint64_t &usageSize, uint64_t &totalSize) {
#ifdef Q_OS_WIN
    totalSize = getTotalPhysMem();
    uint64_t freeSize = getAvailPhysMem();
    usageSize = totalSize - freeSize;
#else
    uint64_t totalMem = 0, freeMem = 0;
    if(readProcMemInfo(totalMem, freeMem)) {
        totalSize = totalMem / 1024; // MemTotal是以kB为单位，转换为MB
        usageSize = (totalMem - freeMem) / 1024; // 计算已使用的内存并转换为MB
    } else {
        totalSize = 0;
        usageSize = 0;
    }
#endif
}

void QMemoryMonitor::getSystemVirtualMemory(uint64_t &usageSize, uint64_t &totalSize) {
#ifdef Q_OS_WIN
    totalSize = getTotalVirtualMem();
    uint64_t freeSize = getAvailVirtualMem();
    usageSize = totalSize - freeSize;
#else
    // Linux does not provide a direct way to get virtual memory usage at system level.
    // This would require more complex parsing or assumptions based on available data.
    totalSize = 0;
    usageSize = 0;
#endif
}

void QMemoryMonitor::getProcessPhysicalMemory(qint64 pid, uint64_t &usageSize) {
#ifdef Q_OS_WIN
    if (pid == 0) pid = GetCurrentProcessId();

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (hProcess == NULL) {
        usageSize = -1;
        return;
    }

    PROCESS_MEMORY_COUNTERS pmc;
    if (!GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
        CloseHandle(hProcess);
        usageSize = -1;
        return;
    }

    CloseHandle(hProcess);
    usageSize = pmc.WorkingSetSize;
#else
    if (pid == 0) pid = getpid();

    QString path = QString("/proc/%1/status").arg(pid);
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly)) {
        usageSize = -1;
        return;
    }

    QTextStream in(&file);
    QString line;
    while (!in.atEnd()) {
        line = in.readLine();
        if (line.startsWith("VmRSS:")) {
            double vmRSS = line.split(' ', Qt::SkipEmptyParts)[1].toDouble(); // VmRSS是以kB为单位
            usageSize = vmRSS / 1024.0;
            break;
        }
    }

    file.close();
#endif
}

void QMemoryMonitor::getProcessVirtualMemory(qint64 pid, uint64_t &usageSize) {
#ifdef Q_OS_WIN
    if (pid == 0) pid = GetCurrentProcessId();

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (hProcess == NULL) {
        usageSize = -1;
        return;
    }

    PROCESS_MEMORY_COUNTERS pmc;
    if (!GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
        CloseHandle(hProcess);
        usageSize = -1;
        return;
    }

    CloseHandle(hProcess);
    usageSize = pmc.PagefileUsage;
#else
    if (pid == 0) pid = getpid();

    QString path = QString("/proc/%1/status").arg(pid);
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly)) {
        usageSize = 0;
//        totalSize = 0;
        return;
    }

    QTextStream in(&file);
    QString line;
    while (!in.atEnd()) {
        line = in.readLine();
        if (line.startsWith("VmSize:")) {
//            double vmSize = line.split(' ', Qt::SkipEmptyParts)[1].toDouble(); // VmSize是以kB为单位
//            totalSize = vmSize / 1024.0;
        } else if (line.startsWith("VmRSS:")) {
            double vmRSS = line.split(' ', Qt::SkipEmptyParts)[1].toDouble(); // VmRSS是以kB为单位
            usageSize = vmRSS / 1024.0;
        }
//        if (totalSize != 0 && usageSize != 0) break; // 提前退出循环
        if (usageSize != 0) break; // 提前退出循环
    }

    file.close();
#endif
}

#ifdef Q_OS_WIN
DWORDLONG QMemoryMonitor::getTotalPhysMem() {
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    return memInfo.ullTotalPhys;
}

DWORDLONG QMemoryMonitor::getAvailPhysMem() {
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    return memInfo.ullAvailPhys;
}

DWORDLONG QMemoryMonitor::getTotalVirtualMem() {
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    return memInfo.ullTotalPageFile;
}

DWORDLONG QMemoryMonitor::getAvailVirtualMem() {
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    return memInfo.ullAvailPageFile;
}
#else
bool QMemoryMonitor::readProcMemInfo(uint64_t &totalMem, uint64_t &freeMem) {
    QFile file("/proc/meminfo");
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open /proc/meminfo";
        return false;
    }

    QTextStream in(&file);
    QString line;

    while (!in.atEnd()) {
        line = in.readLine();
        if (line.startsWith("MemTotal:")) {
            totalMem = line.split(' ', Qt::SkipEmptyParts)[1].toULongLong();
        } else if (line.startsWith("MemFree:")) {
            freeMem = line.split(' ', Qt::SkipEmptyParts)[1].toULongLong();
        }
        if (totalMem != 0 && freeMem != 0) break; // 提前退出循环
    }

    file.close();

    return totalMem != 0 && freeMem != 0;
}
#endif
